package ca.scotthyndman.as2haxe.output;

/**
 * Defines options for source code formatting.
 * 
 * TODO comment better
 */
public class FormattingOptions {

	private BracePolicy bracePolicy = new BracePolicy();

	private WhiteSpacePolicy whitespacePolicy = new WhiteSpacePolicy();

	private WrappingPolicy wrapPolicy = new WrappingPolicy();

	// ====== CONSTRUCTION

	/**
	 * Constructs a new formatting options object.
	 */
	public FormattingOptions() {

	}

	// ====== PROPERTIES

	/**
	 * Returns the brace policy.
	 */
	public BracePolicy getBracePolicy() {
		return bracePolicy;
	}

	/**
	 * Sets the brace policy.
	 * 
	 * @param bracePolicy
	 *            the policy
	 */
	public void setBracePolicy(BracePolicy bracePolicy) {
		this.bracePolicy = bracePolicy;
	}

	/**
	 * Returns the whitespace policy.
	 * 
	 * @return the policy
	 */
	public WhiteSpacePolicy getWhitespacePolicy() {
		return whitespacePolicy;
	}

	/**
	 * Sets the whitespace policy.
	 * 
	 * @param whitespacePolicy
	 *            the policy
	 */
	public void setWhitespacePolicy(WhiteSpacePolicy whitespacePolicy) {
		this.whitespacePolicy = whitespacePolicy;
	}

	/**
	 * Returns the wrapping policy.
	 * 
	 * @return the policy
	 */
	public WrappingPolicy getWrappingPolicy() {
		return wrapPolicy;
	}

	/**
	 * Sets the wrapping policy.
	 * 
	 * @param wrappingPolicy
	 *            the policy
	 */
	public void setWrappingPolicy(WrappingPolicy wrappingPolicy) {
		this.wrapPolicy = wrappingPolicy;
	}

	// ====== CLASSES

	/**
	 * Defines how whitespace should be used in the output.
	 */
	public class WhiteSpacePolicy {
		private boolean beforeTypedefBrace = true;

		private boolean afterImplementsComma = true;

		private boolean beforeAssign = true;
		
		private boolean afterAssign = true;
		
		private boolean beforeBinary = true;
		
		private boolean afterBinary = true;
		
		private boolean beforePrefix = false;
		
		private boolean afterPrefix = false;
		
		private boolean beforePostfix = false;
		
		private boolean afterPostfix = false;
		
		public void setBeforeTypedefBrace(boolean beforeTypedefBrace) {
			this.beforeTypedefBrace = beforeTypedefBrace;
		}

		public boolean isBeforeTypedefBrace() {
			return beforeTypedefBrace;
		}

		public void setAfterImplementsComma(boolean afterImplementsComma) {
			this.afterImplementsComma = afterImplementsComma;
		}

		public boolean isAfterImplementsComma() {
			return afterImplementsComma;
		}

		public boolean isAfterAssign() {
			return afterAssign;
		}

		public void setAfterAssign(boolean afterAssign) {
			this.afterAssign = afterAssign;
		}

		public boolean isAfterBinary() {
			return afterBinary;
		}

		public void setAfterBinary(boolean afterBinary) {
			this.afterBinary = afterBinary;
		}

		public boolean isAfterPostfix() {
			return afterPostfix;
		}

		public void setAfterPostfix(boolean afterPostfix) {
			this.afterPostfix = afterPostfix;
		}

		public boolean isAfterPrefix() {
			return afterPrefix;
		}

		public void setAfterPrefix(boolean afterPrefix) {
			this.afterPrefix = afterPrefix;
		}

		public boolean isBeforeAssign() {
			return beforeAssign;
		}

		public void setBeforeAssign(boolean beforeAssign) {
			this.beforeAssign = beforeAssign;
		}

		public boolean isBeforeBinary() {
			return beforeBinary;
		}

		public void setBeforeBinary(boolean beforeBinary) {
			this.beforeBinary = beforeBinary;
		}

		public boolean isBeforePostfix() {
			return beforePostfix;
		}

		public void setBeforePostfix(boolean beforePostfix) {
			this.beforePostfix = beforePostfix;
		}

		public boolean isBeforePrefix() {
			return beforePrefix;
		}

		public void setBeforePrefix(boolean beforePrefix) {
			this.beforePrefix = beforePrefix;
		}

	}

	/**
	 * Defines how source code should be wrapped when it gets too long.
	 */
	public class WrappingPolicy {

		private int maxCharacters = 80;

		private int wrappedIndentation;

		//
		// Class
		//
		private WrapBehavior extendsClause = WrapBehavior.WHEN_NECESSARY;

		private WrapBehavior implementsClause = WrapBehavior.WRAP_FIRST;

		//
		// Properties
		//

		public int getMaxCharacters() {
			return maxCharacters;
		}

		public void setMaxCharacters(int maxCharacters) {
			this.maxCharacters = maxCharacters;
		}

		public int getWrappedIndentation() {
			return wrappedIndentation;
		}

		public void setWrappedIndentation(int wrappedIndentation) {
			this.wrappedIndentation = wrappedIndentation;
		}

		public WrapBehavior getExtendsClause() {
			return extendsClause;
		}

		public void setExtendsClause(WrapBehavior extendsClause) {
			this.extendsClause = extendsClause;
		}

		public WrapBehavior getImplementsClause() {
			return implementsClause;
		}

		public void setImplementsClause(WrapBehavior implementsClause) {
			this.implementsClause = implementsClause;
		}
	}

	public enum WrapBehavior {
		/** Never wraps */
		NEVER,
		/** Only wraps elements as necessary */
		WHEN_NECESSARY,
		/** Always wraps the first, and other elements as necessary */
		WRAP_FIRST,
		/** Places every element on its own line */
		WRAP_ALL;
	}

	/**
	 * Defines how braces should be positioned in different situations.
	 */
	public class BracePolicy {

		private BracePosition block = BracePosition.SAME_LINE;

		private BracePosition typeDef = BracePosition.SAME_LINE;

		public void setBlock(BracePosition block) {
			this.block = block;
		}

		public BracePosition getBlock() {
			return block;
		}

		public void setTypeDef(BracePosition typeDef) {
			this.typeDef = typeDef;
		}

		public BracePosition getTypeDef() {
			return typeDef;
		}
	}

	/**
	 * Enumerates possible brace positions.
	 */
	public enum BracePosition {
		SAME_LINE, NEXT_LINE;
	}
}
